package model;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import javax.swing.ImageIcon;

public class SpriteCollection implements Collisionable,Iterable<Sprite> {

	Set<Sprite> sprites =  new HashSet<Sprite>();
	private ImageIcon collImg;
	private CompositeCollisionMap collMap = new CompositeCollisionMap();
	private int[] position = {0,0};
	
	public synchronized boolean add(Sprite s){
		if(sprites.size()==0){
			this.position[0] = s.getPosition()[0];
			this.position[1] = s.getPosition()[1];
		}
		int[] relativePos = new int[2];
		relativePos[0]=s.getPosition()[0]-position[0];
		relativePos[1]=s.getPosition()[1]-position[1];
		int[] optimizedDecal = collMap.add(relativePos,s.getCollisionMap());
		if(optimizedDecal!=null){
			 position[0]+=optimizedDecal[0];
			 position[1]+=optimizedDecal[1];
		 }
		
		return sprites.add(s);
	}
	public void addAll(Collection<Sprite> col){
		for (Sprite s : col) {
			add(s);
		}
	}
	public boolean contains(Sprite s){
		return sprites.contains(s);
	}
	public int size(){
		return sprites.size();
	}
	public synchronized boolean removeSprite(Sprite s){
		boolean isremoved = sprites.remove(s);
		if(isremoved){
			int[] relativePos = new int[2];
			 relativePos[0]=s.getPosition()[0]-position[0];
			 relativePos[1]=s.getPosition()[1]-position[1];
			collMap.remove(relativePos,s.getCollisionMap());
			//if the removed sprite colisionMap is at the top/left side of the collection, we must recalc the position
			if(   position[0]>=s.getPosition()[0] || position[1]>=s.getPosition()[1]){
				int[] decal = recalcPosition();//if position has changed, we must recalc the collision map too !
				
				if(decal != null){
					collMap = collMap.getExtract(decal[0], decal[1], collMap.getWidth(), collMap.getHeight());
				}
					 //int[] relativePos = new int[2];
					 //relativePos[0]=s.getPosition()[0]-position[0];
					 //relativePos[1]=s.getPosition()[1]-position[1];
					 //removes the collisionMap et the given position ,optimize the new grid and return decal position
					 //int[] optimizedDecal = collMap.remove(relativePos,s.getCollisionMap());
					 //if(optimizedDecal!=null){
					 //	 position[0]+=optimizedDecal[0];
					 //	 position[1]+=optimizedDecal[1];
					 //}
				
			}
		}
		return isremoved;
	}
	
	
	private synchronized int[] recalcPosition(){
		if(sprites.size()!=0){
			
			int[] toPos = null;
			//when we remove a Sprite, the position and the collisionMap could change. we must recalc this.
			
			for (Sprite s : sprites) {
				if(toPos==null){
					toPos=new int[2];
					toPos[0] = s.getPosition()[0];
					toPos[1] = s.getPosition()[1];
				}
				if(s.getPosition()[0]<toPos[0]){
					toPos[0]=s.getPosition()[0];
				}
				if(s.getPosition()[1]<toPos[1]){
					toPos[1]=s.getPosition()[1];
				}
			}
			
			if(position[0]!=toPos[0] || position[1]!=toPos[1]){
				int[] decal = {toPos[0]-position[0],toPos[1]-position[1]};
				position[0]=toPos[0];
				position[1]=toPos[1];
				return decal;
			}else{
				return null;
			}
		}else return null;
	}
	public void refresh(){
		recalcPosition();
	}
	
	public CompositeCollisionMap getCollisionMap(){
		return collMap;
	}
	
	public synchronized ImageIcon getCollisionMapImage(){
		
		createCollisionMapImage();
		
		return collImg;
		
	}
	
	private void createCollisionMapImage(){

		int[] color = {250,0,0,75};
		collImg=CollisionUtils.getCollisionMapImage(collMap, color);
	}
	@Override
	public int[] getPosition() {
		// TODO Auto-generated method stub
		return position;
	}
	
	public synchronized void setPosition(int[] newPos){
		int[] decal = new int[2];
		decal[0] = newPos[0]-position[0];
		decal[1] = newPos[1]-position[1];
		move(decal);
	}
	
	public void move(int[] decal){
		move(decal[0],decal[1]);
	}
	public synchronized void move(int x,int y){
			if(sprites.size()>0){
				for (Sprite s : sprites) {
					s.move(x,y);
				}
				position[0] += x;
				position[1] += y;
			}
	}
	
	@Override
	public Iterator<Sprite> iterator() {
		// TODO Auto-generated method stub
		Iterator<Sprite> it = new SPIterator(sprites.iterator());
		return it;
	}
	private class SPIterator implements Iterator<Sprite>{

		Iterator<Sprite> spriteIter;
		Sprite currentSprite;
		
		public SPIterator(Iterator<Sprite> it) {
			spriteIter = it;
		}
		
		@Override
		public boolean hasNext() {
			return spriteIter.hasNext();
		}

		@Override
		public Sprite next() {
			currentSprite = spriteIter.next();
			return currentSprite;
		}

		@Override
		public void remove() {
			//upper.remove(current);
			removeSprite(currentSprite);
		}
		
	}
}
